package com.ccp.dev.workflow.listener;

import com.ccp.dev.core.basic.engine.GroovyScriptEngine;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.form.consts.FormConstants;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.model.BpmNodeScript;
import com.ccp.dev.workflow.model.ProcessRun;
import com.ccp.dev.workflow.model.bpm.ProcessCmd;
import com.ccp.dev.workflow.model.bpm.TaskExecutor;
import com.ccp.dev.workflow.service.BpmNodeScriptService;
import com.ccp.dev.workflow.service.ProcessRunService;
import com.ccp.dev.workflow.service.bpm.BpmNodeUserUtil;
import com.ccp.dev.workflow.service.bpm.thread.TaskThreadService;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * ClassDescribe:
 * 任务事件基类，采用了模板模式
 *
 * @author :wangcheng
 * Date: 2019-05-13
 */
public abstract class BaseTaskListener implements TaskListener {
    protected Logger LOGGER = LoggerFactory.getLogger(BaseTaskListener.class);

    protected String RESULT_NAME="success";
    protected String RESULT_MSG_NAME="msg";

    @Override
    public void notify(DelegateTask delegateTask) {
        TaskEntity taskEntity = (TaskEntity) delegateTask;
        String procDefId = taskEntity.getProcessDefinitionId();
        String nodeId = taskEntity.getTaskDefinitionKey();

        // 获取脚本类型
        int beforeScriptType = getBeforeScriptType();
        // 执行前置脚本
        exeEventScript(delegateTask, beforeScriptType, procDefId, nodeId);
        LOGGER.debug("enter the baseTaskListener notify method...");

        // 执行子类业务逻辑
        execute(delegateTask, procDefId, nodeId);

        // 获取脚本类型
        int scriptType = getScriptType();
        exeEventScript(delegateTask, scriptType, procDefId, nodeId);

    }

    /**
     * 获取脚本类型
     * @return
     */
    protected abstract int getScriptType();

    /**
     * 子类业务逻辑
     * @param delegateTask 任务
     * @param procDefId 流程定义Id
     * @param nodeId 节点id
     */
    protected abstract void execute(DelegateTask delegateTask, String procDefId, String nodeId);

    protected void exeEventScript(DelegateTask delegateTask, int scriptType, String procDefId, String nodeId){

        LOGGER.debug("enter the baseTaskListener exeEventScript method...");
        BpmNodeScriptService bpmNodeScriptService=(BpmNodeScriptService)AppUtil.getBean("bpmNodeScriptService");
        BpmNodeScript scriptModel=bpmNodeScriptService.getScriptByType(nodeId, procDefId,scriptType);
        if(scriptModel==null){
            return;
        }
        String script=scriptModel.getScript();
        if(StringUtil.isEmpty(script)) {
            return;
        }

        GroovyScriptEngine scriptEngine=AppUtil.getBean(GroovyScriptEngine.class);
        Map<String, Object> vars=delegateTask.getVariables();

        vars.put("task", delegateTask);
        scriptEngine.execute(script, vars);
    }

    /**
     * 获取前置脚本类型
     * @return 脚本类型
     */
    protected abstract int getBeforeScriptType();

    /**
     * 是否允许代理。
     * <pre>
     * 1.如果跳过第一个节点，那么忽略第一个节点的代理设置。
     * 2.往下执行才允许代理，如果是驳回不允许代理。
     * </pre>
     * @return
     */
    protected boolean isAllowAgent(){
        //驳回、追回
        ProcessCmd processCmd=TaskThreadService.getProcessCmd();

        if(BpmConst.TASK_BACK_TOSTART.equals(processCmd.isBack())||BpmConst.TASK_BACK.equals(processCmd.isBack())){
            return false;
        }

        //流程启动,并跳过第一个节点
        Short toFirstNode = (Short) TaskThreadService.getToFirstNode();
        TaskThreadService.removeToFirstNode();
        if(toFirstNode!=null && toFirstNode==1){
            return false;
        }

        return true;
    }

    /**
     * 根据组执行人取得任务执行人。
     * @param taskExecutor
     * @return
     */
    protected List<TaskExecutor> getByTaskExecutor(TaskExecutor taskExecutor){
        List<TaskExecutor> list=new ArrayList<TaskExecutor>();
        if(taskExecutor.getExactType()==TaskExecutor.EXACT_NOEXACT){
            list.add(taskExecutor);
        }
        else{
            List<SysUser> userList=BpmNodeUserUtil.getUserListByExecutor(taskExecutor);
            for(SysUser sysUser:userList){
                list.add(TaskExecutor.getTaskUser(sysUser.getUserId(), sysUser.getUsername()));
            }
        }
        return list;
    }

    protected String getNotAssignMessage(TaskExecutor taskExecutor){
        String message="{0}:【{1}】没有配置人员!";
        String type="";
        switch (taskExecutor.getType()){
            case TaskExecutor.USER_TYPE_ORG:
                type="部门";
                break;
            case TaskExecutor.USER_TYPE_POS:
                type="岗位";
                break;
            case TaskExecutor.USER_TYPE_ROLE:
                type="角色";
                break;
        }
        return StringUtil.formatParamMsg(message, type,taskExecutor.getExecutor()).toString();
    }

    /**
     * 获取执行人。
     * @param list
     * @return
     */
    protected List<TaskExecutor> getByTaskExecutors(List<TaskExecutor> list){
        List<TaskExecutor> exSet=new ArrayList<>();
        for(TaskExecutor ex:list){
            List<TaskExecutor> tmp= getByTaskExecutor(ex);
            exSet.addAll(tmp);
        }
        return exSet;
    }

    /**
     * 获取表单数据密级
     * @param delegateTask 任务实体
     * @return int 密级数据
     */
    protected int getDataPrivacyLevel(DelegateTask delegateTask){
        ProcessRunService processRunService = AppUtil.getBean(ProcessRunService.class);
        String instanceId = delegateTask.getProcessInstanceId();
        ProcessRun processRun  = processRunService.getByProcInstanceId(instanceId);
        int dataPrivacyLevel = 1;
        if(BeanUtils.isNotEmpty(delegateTask.getVariable(FormConstants.DATA_PRIVACY_LEVEL))){
            dataPrivacyLevel = Integer.parseInt(delegateTask.getVariable(FormConstants.DATA_PRIVACY_LEVEL).toString());
        }else{
            try{
                if(null!=processRun){
                    dataPrivacyLevel = processRunService.getPrivacyLevelByProcessRun(processRun);
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        return dataPrivacyLevel;
    }

}
